#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const readline = require('readline');

// 显示帮助信息
function showHelp() {
  console.log(`
    Usage: get-dir-tree [dirPath] [shouldDeepTraverse] [outputPath] [ignorePatterns]

    Options:
      dirPath            目标目录路径，默认为当前目录。
      shouldDeepTraverse 控制遍历深度，0表示全部遍历，1表示只获取当前层，其他正整数表示对应层数，默认为1。
      outputPath         输出文件路径，默认不保存到文件。
      ignorePatterns     过滤规则，默认过滤.git，node_modules。
      -h, --help         显示帮助信息。

    Examples:
      get-dir-tree ./ 1 
      get-dir-tree ./ 2 outputPath
      get-dir-tree ./ 0 outputPath
      get-dir-tree -h (or --help) for help
  `);
}

// 创建readline接口实例
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

// 解析命令行参数并开始对话
async function startDialogue() {
  // 如果有参数且不是帮助标志，则直接使用这些参数
  const args = process.argv.slice(2);
  if (args.includes('-h') || args.includes('--help')) {
    showHelp();
    process.exit(0);
  }

  let dirPath = args[0];
  let shouldDeepTraverse = args[1];
  let outputPath = args[2];
  // 设置忽略模式
  let ignorePatterns = args[3];

  // 如果缺少参数，则通过对话方式获取
  if (!dirPath) {
    dirPath = await askQuestion('请输入目标目录路径（默认为当前目录）：') || './';
  }
  if (shouldDeepTraverse === undefined) {
    shouldDeepTraverse = await askQuestion('请输入应遍历的最大深度（0为不限制,但是文件过多或有一些特殊字符的文件可能会出现报错，1为仅当前层，默认为1）：') || '1';
    shouldDeepTraverse = shouldDeepTraverse.toLowerCase() === '0' ? Infinity : parseInt(shouldDeepTraverse, 10) || 1;
  }
  if (outputPath === undefined) {
    let fileName = await askQuestion('请输入输出文件名称（留空则不保存到文件）：')
    outputPath = fileName ? fileName + '.md' : null;
  }
  if (ignorePatterns === undefined) {
    let filterList = await askQuestion('请输入忽略规则（多个规则用逗号分隔），默认过滤.git，node_modules：')
    ignorePatterns = filterList ? filterList?.split(/[,，]/) : ['.git', 'node_modules'];
  }
  rl.close(); // 关闭readline接口



  // 打印或保存结果
  const result = dirPath + '\n' + treeToMarkdown(dirPath, '', true, ignorePatterns, shouldDeepTraverse);

  if (outputPath) {
    let text = "```bash\n" + result + "\n```";
    fs.writeFileSync(outputPath, text);
    console.log(`目录结构已保存至: ${outputPath}`);
  } else {
    console.log(result);
  }
}

// 提问函数
function askQuestion(question) {
  return new Promise(resolve => {
    // 禁用快速编辑模式
    process.stdin.setRawMode(false);
    rl.question(question, (answer) => {
      // 恢复快速编辑模式
      process.stdin.setRawMode(true);
      resolve(answer);
    });
  });
}

// 树状结构转换为Markdown格式函数
function treeToMarkdown(dirPath, prefix = '', isLast = true, ignorePatterns = [], depth = Infinity, currentDepth = 0) {
  let markdown = '';
  try {
    if (currentDepth >= depth) return ''; // 达到最大深度时停止递归

    const entries = fs.readdirSync(dirPath, { withFileTypes: true });
    entries.sort((a, b) => b.isDirectory() - a.isDirectory() || a.name.localeCompare(b.name));

    entries.forEach((entry, index) => {
      if (isIgnored(entry.name, ignorePatterns)) return;

      const isEntryLast = index === entries.length - 1;
      const newPrefix = isEntryLast ? '└── ' : '├── ';
      const entryName = entry.isDirectory() ? entry.name + '/' : entry.name;
      markdown += `${prefix}${newPrefix}${entryName}\n`;

      if (entry.isDirectory()) { // 检查是否继续遍历子目录
        const nextPrefix = isEntryLast ? '    ' : '│   ';
        markdown += treeToMarkdown(path.join(dirPath, entry.name), prefix + nextPrefix, isEntryLast, ignorePatterns, depth, currentDepth + 1);
      } else if (entry.isSymbolicLink()) {
        try {
          const resolvedPath = fs.readlinkSync(path.join(dirPath, entry.name));
          markdown += `${prefix}    → ${resolvedPath}\n`;
        } catch (err) {
          console.error(`无法解析符号链接: ${entry.name}`);
        }
      }
    });
  } catch (err) {
    console.error(`读取目录时出错: ${dirPath}`, err);
  }

  return markdown;
}

// 忽略规则函数
function isIgnored(entryName, ignorePatterns) {
  return ignorePatterns.some(pattern => entryName.startsWith(pattern));
}

startDialogue();